package cmd

import (
	"fmt"
	"gitee.com/hexug/go-tools/common"
	"gitee.com/hexug/go-tools/ioc"
	"gitee.com/hexug/go-tools/ioc/log"
	"gitee.com/hexug/go-tools/logger"
	"gitee.com/hexug/kube-sync/cmd/migrate"
	"gitee.com/hexug/kube-sync/cmd/sync"
	"gitee.com/hexug/kube-sync/conf"
	"gitee.com/hexug/kube-sync/version"
	"github.com/spf13/cobra"
	"os"
	"strings"
)

var (
	v bool
	V bool

	debug      bool
	configType string
	configPath string

	rootCmd = &cobra.Command{
		/*
			Use是单行用法消息。
			建议的语法如下：
			[]标识可选参数。不包含在括号中的参数是必需的。
			...表示可以为上一个参数指定多个值。
			\表示互斥信息。可以使用分隔符左侧的参数或分隔符右侧的参数。不能在一次使用命令时同时使用两个参数。
			{}在需要其中一个参数时分隔一组互斥参数。如果参数为可选，它们用括号（[]）括起来。
			示例：add [-F file | -D dir]... [-f format] file
		*/
		Use: "kube-sync",
		// short是“help”输出中显示的简短描述。
		Short: "kube-sync是一个用于同步、克隆、迁移kubernetes资源的工具",
		// Long是“help＜this command＞”输出中显示的长消息。
		Long: "kube-sync是一个用于同步、克隆、迁移kubernetes资源的工具",
		// Example是如何使用该命令的示例。
		Example: "kube-sync -v",

		Run: func(cmd *cobra.Command, args []string) {
			err := cmd.Help()
			cobra.CheckErr(err)
		},
	}
)

func Execute() {
	rootCmd.AddCommand(sync.Cmd)
	rootCmd.AddCommand(migrate.Cmd)
	if err := rootCmd.Execute(); err != nil {
		return
	}
}

func init() {
	rootCmd.SetHelpCommand(&cobra.Command{Hidden: true})
	rootCmd.AddCommand(completionCmd)
	rootCmd.SetUsageTemplate(zhUsageTemplate)
	rootCmd.SetHelpTemplate(zhHelpTemplate)
	rootCmd.SetVersionTemplate(zhVersionTemplate)

	rootCmd.PersistentFlags().BoolVarP(&debug, "debug", "d", false, "开启debug模式")
	rootCmd.PersistentFlags().BoolVarP(&v, "version", "v", false, "版本信息")
	rootCmd.PersistentFlags().BoolVarP(&V, "Version", "V", false, "长版本信息")
	rootCmd.PersistentFlags().StringVarP(&configType, "config-type", "t", "default", "指定加载配置的类型")
	rootCmd.PersistentFlags().StringVarP(&configPath, "config-path", "f", "", "指定配置文件")
	// 在 PersistentPreRun 中统一处理版本输出逻辑
	rootCmd.PersistentPreRun = func(cmd *cobra.Command, args []string) {
		// 如果设置了 -v 或 --version，输出短版本信息并退出
		if v {
			fmt.Println(version.ShortVersion())
			os.Exit(0)
		}
		// 如果设置了 -V 或 --Version，输出长版本信息并退出
		if V {
			fmt.Println(version.FullVersion())
			os.Exit(0)
		}
		conf.RegisterDefaultConf()
		logConf := ioc.Container.GetConf(log.ConfName).(*log.Log)
		if debug {
			logConf.Level = "debug"
			logger.L().Debug("debug模式已开启")
		}
		// 初始化日志
		common.InitLog(logConf)
		if configPath != "" {
			logger.L().Debug("触发文件加载配置")
			configType = "file"
		}
		switch configType {
		case "file":
			logger.L().Debugf("从file加载配置文件: %s", configPath)
			ioc.Container.LoadConfigRequest.ConfigFile.Enabled = true
			ioc.Container.LoadConfigRequest.ConfigFile.Path = configPath
		case "env":
			logger.L().Debug("从环境变量加载配置")
			ioc.Container.LoadConfigRequest.ConfigEnv.Enabled = true
		case "default":
			logger.L().Debug("使用默认配置")
		default:
			logger.L().Debug("选择的加载配置类型有误,目前只允许['file','env','default']")
			return
		}
		ioc.Container.InitConfs()
		logger.L().Debug("配置加载完成。")
		ioc.Container.InitApps()

		logConf = ioc.Container.GetConf(log.ConfName).(*log.Log)
		if debug {
			logConf.Level = "debug"
		} else {
			if logConf.Level == "debug" {
				debug = true
			}
		}
		logger.L().Debugf("app初始化完成，debug是否开启: %t", debug)
		// 初始化日志
		common.InitLog(logConf)
	}
}

// 中文化 UsageTemplate
var zhUsageTemplate = `用法:{{if .Runnable}}
  {{.UseLine}}{{end}}{{if .HasAvailableSubCommands}}
  {{.CommandPath}} [命令]{{end}}{{if gt (len .Aliases) 0}}

别名:
  {{.NameAndAliases}}{{end}}{{if .HasExample}}

示例:
{{.Example}}{{end}}{{if .HasAvailableSubCommands}}{{$cmds := .Commands}}{{if eq (len .Groups) 0}}

可用命令:{{range $cmds}}{{if (or .IsAvailableCommand (eq .Name "help"))}}
  {{rpad .Name .NamePadding }} {{.Short}}{{end}}{{end}}{{else}}{{range $group := .Groups}}

{{.Title}}{{range $cmds}}{{if (and (eq .GroupID $group.ID) (or .IsAvailableCommand (eq .Name "help")))}}
  {{rpad .Name .NamePadding }} {{.Short}}{{end}}{{end}}{{end}}{{if not .AllChildCommandsHaveGroup}}

其他命令:{{range $cmds}}{{if (and (eq .GroupID "") (or .IsAvailableCommand (eq .Name "help")))}}
  {{rpad .Name .NamePadding }} {{.Short}}{{end}}{{end}}{{end}}{{end}}{{end}}{{if .HasAvailableLocalFlags}}

参数:
{{.LocalFlags.FlagUsages | trimTrailingWhitespaces}}{{end}}{{if .HasAvailableInheritedFlags}}

全局参数:
{{.InheritedFlags.FlagUsages | trimTrailingWhitespaces}}{{end}}{{if .HasHelpSubCommands}}

额外帮助主题:{{range .Commands}}{{if .IsAdditionalHelpTopicCommand}}
  {{rpad .CommandPath .CommandPathPadding}} {{.Short}}{{end}}{{end}}{{end}}{{if .HasAvailableSubCommands}}

使用 "{{.CommandPath}} [命令] --help" 查看某个命令的详细帮助。{{end}}
`

// 中文化 HelpTemplate
var zhHelpTemplate = `{{with (or .Long .Short)}}{{. | trimTrailingWhitespaces}}

{{end}}{{if or .Runnable .HasSubCommands}}{{.UsageString}}{{end}}`

// 中文化 VersionTemplate
var zhVersionTemplate = `{{with .DisplayName}}{{printf "%s " .}}{{end}}{{printf "版本 %s" .Version}}
`

var completionCmd = &cobra.Command{
	Use:   "completion [bash|zsh|fish|powershell]",
	Short: "生成补全脚本",
	Long: `加载补全内容:

Bash:
  source <(kube-sync completion bash)

Zsh:
  source <(kube-sync completion zsh)

Fish:
  kube-sync completion fish | source

PowerShell:
  kube-sync completion powershell | Out-String | Invoke-Expression

提示:
  当需要补全-x或者--xx参数的时候，需要输入-或者-- 再接<TAB>
  如: kube-sync - <TAB>
`, Args: cobra.ExactArgs(1),
	ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
		shells := []string{"bash", "zsh", "fish", "powershell"}
		var matches []string
		for _, s := range shells {
			if strings.HasPrefix(s, toComplete) {
				matches = append(matches, s)
			}
		}
		return matches, cobra.ShellCompDirectiveNoFileComp
	},
	RunE: func(cmd *cobra.Command, args []string) error {
		switch args[0] {
		case "bash":
			return rootCmd.GenBashCompletion(os.Stdout)
		case "zsh":
			return rootCmd.GenZshCompletion(os.Stdout)
		case "fish":
			return rootCmd.GenFishCompletion(os.Stdout, true)
		case "powershell":
			return rootCmd.GenPowerShellCompletionWithDesc(os.Stdout)
		default:
			return fmt.Errorf("unsupported shell type: %s", args[0])
		}
	},
}
